package com.my12306.train.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.my12306.common.constant.CommonConstants;
import com.my12306.common.enums.CodeEnum;
import com.my12306.common.model.vo.PageVo;
import com.my12306.common.util.PageUtils;
import com.my12306.common.util.SnowflakeIdWorker;
import com.my12306.common.util.response.ResponseData;
import com.my12306.train.dao.PlanDao;
import com.my12306.train.exception.SeatException;
import com.my12306.train.model.entity.CarriageEntity;
import com.my12306.train.model.entity.PlanEntity;
import com.my12306.train.model.entity.SeatEntity;
import com.my12306.train.model.entity.TrainScheduleEntity;
import com.my12306.train.model.vo.PlanParamsVo;
import com.my12306.train.service.PlanService;
import com.my12306.train.service.SeatService;
import com.my12306.train.service.TrainScheduleService;
import com.my12306.train.utils.TrainUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;


@Service("planService")
public class PlanServiceImpl extends ServiceImpl<PlanDao, PlanEntity> implements PlanService {

    @Autowired
    private SeatService seatService;
    @Autowired
    private TrainScheduleService trainScheduleService;

    private final static String dateStr = "yyyy-MM-dd";
    /**
     * 时间格式化类
     */
    private  DateTimeFormatter  oneFormate= DateTimeFormatter.ofPattern(dateStr);
    @Override
    public PageUtils queryPlanPage(PageVo pageVo) {
        pageVo = pageVo.init();
        List<PlanEntity> trains = this.baseMapper.queryPlanPage(pageVo, CommonConstants.LogicDelete.no_delet.getValue());
        if (trains != null) {
            Integer dataCount = queryPlanCount(pageVo, CommonConstants.LogicDelete.no_delet.getValue());
            System.out.println("数据总量：" + dataCount);
            return PageUtils.build(pageVo, trains, dataCount);
        }
        return null;
    }

    @Override
    public Integer queryPlanCount(PageVo pageVo, int logicDelete) {
        Integer count = this.baseMapper.queryPlanCount(pageVo, logicDelete);
        return count;
    }

    @Override
    @Transactional
    public ResponseData savePlan(PlanEntity plan) {
        if (plan != null&&plan.getPercentage()!=null&&plan.getTrainCode()!=null&&plan.getCoachNumber()!=null) {
            plan.setId(SnowflakeIdWorker.generateId());
            plan.setCreateDate(new Date());
            plan.setUpdateDate(new Date());
            try {
                //生成席位并且根据计划中的百分比生成对应车厢在对应车站的席位数
                if (generatingSeatTicket(plan)) {

                    int insert = this.baseMapper.insert(plan);
                    return ResponseData.ok();
                } else {
                    return ResponseData.fail(CodeEnum.ADD_FAIL.getCode(), "生成席位信息失败,请联系管理员");
                }
            }catch (Exception e){
                try {
                    throw new SeatException("生成席位信息失败,请联系管理员",e);
                } catch (SeatException ex) {
                    throw new RuntimeException("生成席位信息失败,请联系管理员！", ex);
                }
            }
        }
        return ResponseData.fail(CodeEnum.ADD_FAIL.getCode(),"生成席位信息失败,原因：计划的数据不符合规范或者数据不完整！");
    }

    /**
     * 自动生成票据信息添加到席位信息立马
     * 1.查出所有车厢
     * 2.然后生成票据数据添加的票据表
     */
    private Boolean generatingSeatTicket(PlanEntity plan){
        if (plan!=null){

            //标记是否已经生成过计划中的具体席位数
            boolean p = false;
            //1.遍历生成席位
            //生成席位之前先检查是否已经生成过
            List<SeatEntity> isCreate =  this.seatService.querySeatsByTrainCode(plan.getTrainCode());
            //判断是否已经生成过了
            if (isCreate!=null&&isCreate.size()>0){
//                如果已经生成过初始化数据了,则每个车厢的席位都已经生成，先找出该车厢的所有席位，
//                然后再根据计划修改车厢在车站中的百分比的席位 ，并且修改起始站
                //生成计划需要的席位数据 并添加
                List<SeatEntity> allocated = getAllocated(isCreate, plan);
                List<List<SeatEntity>> result = new ArrayList<>();
                result.add(allocated);
                //修改
                this.seatService.updateBatchSeats(result);
                p=true;
                return true;
            }
            log.error("===================>没生成过席位");
            /**
             * 以下是没生成过席位的
             */
            //2.查询所有车厢
            List<CarriageEntity> entities = queryCoachByTrainCode(plan.getTrainCode(), CommonConstants.LogicDelete.no_delet.getValue());
            AtomicBoolean isError= new AtomicBoolean(false);
            List<List<SeatEntity>> seatList = entities.stream().map(carriage -> {

                if (!carriage.getSitNumber().equals(0)) {
                    //初始化数据  并且把对应部分的席位改成计划中需要的进行一起添加
                    List<SeatEntity> list = createSeatList(carriage, plan);
                    if (list != null && list.size() > 0) {
                        return list;
                    } else {
                        log.error("出现第一次error");
                        isError.set(true);
                        return null;
                    }
                }else{
                    return null;
                }
            }).filter(x->{
                return x!=null;
            }).collect(Collectors.toList());
            //中间生成数据出现了错误直接返回
            if (isError.get()){
                return false;
            }
            log.error("========>需要添加的席位数据："+seatList);
            //3.添加到票据数据库中
            if (seatService.saveBatchSeat(seatList)) {

                return true;
            }else{
                log.error("generatingSeatTicket 添加失败！");
               return false;
            }

        }
        return false;
    }

    private List<SeatEntity> getAllocated(List<SeatEntity>all , PlanEntity plan){
        String tr = plan.getCoachNumber().toString();
        List<SeatEntity> planCoachSeat = all.stream().filter(item -> {
            return item.getCoachNumber().equals(tr);
        }).distinct().collect(Collectors.toList());
        int totalSeat = planCoachSeat.size();
        //未分配的席位
        List<SeatEntity> unAllocated = planCoachSeat.stream().filter(item -> {
            return item.getShowStatus().equals(0);
        }).collect(Collectors.toList());
        int  needSeat = (int) (totalSeat * (Integer.parseInt(plan.getPercentage()) * 0.01));
        List<SeatEntity> allocated = new ArrayList<>();
        needSeat=needSeat<unAllocated.size()?needSeat:unAllocated.size();
        for (int i = 0 ; i < needSeat; i++) {
            SeatEntity seatEntity = unAllocated.get(i);
            seatEntity.setShowStatus(1);
            seatEntity.setStartStation(plan.getStationName());
            seatEntity.setLogicDelete(CommonConstants.LogicDelete.no_delet.getValue());
            allocated.add(seatEntity);
        }
        return allocated.size()>0?allocated:null;
    }

    /**
     * 根据车厢生成席位数据
     * @param carriageEntity
     * @param planEntity
     * @return
     */
    private List<SeatEntity>createSeatList(CarriageEntity carriageEntity,PlanEntity planEntity){
        List<SeatEntity> seats = new ArrayList<>();
        int sitCount = carriageEntity.getSitNumber();
        // 查询发车时间
        TrainScheduleEntity trainScheduleEntity = this.trainScheduleService.queryTrainScheduleByTrainCode(planEntity.getTrainCode(),CommonConstants.LogicDelete.no_delet.getValue());
        log.error("车次的发车时间对象："+trainScheduleEntity);
        if (trainScheduleEntity==null)return null;
        StringBuffer stringBuffer = null;
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
        //车厢编号
        Long coachNumber = Long.parseLong(carriageEntity.getCoachNumber());
        //判断是否是计划中的车厢如果是直接根据百分比生成
        boolean p = planEntity.getCoachNumber().equals(coachNumber);
        for (int i = 0 ; i <sitCount;i++){
            stringBuffer = new StringBuffer();
            SeatEntity seatEntity = new SeatEntity();
            seatEntity.setSeatId(SnowflakeIdWorker.generateId());
            seatEntity.setCreateDate(new Date());
            seatEntity.setUpdateDate(new Date());
            seatEntity.setSeatNo(i);
            seatEntity.setSeatStatus(0);
            seatEntity.setShowStatus(0);
            Date startTime = trainScheduleEntity.getStartTime();
            //计算 发车时间为4天后
            String dateStr = simpleDateFormat.format(startTime);
            seatEntity.setStartDate(getDate(dateStr,4));
            String startStation = trainScheduleEntity.getStartStation();
            String endStation = trainScheduleEntity.getEndStation();
            String trainCode = planEntity.getTrainCode();

            log.error("startStation:"+startStation+",endStation："+endStation+",trainCode:"+trainCode+",coachNumber:"+coachNumber);
            if (startStation!=null&&endStation!=null&&trainCode!=null&&coachNumber!=null) {
                seatEntity.setStartStation(startStation);
                stringBuffer.append(startStation).append("-").append(endStation);
                seatEntity.setInitStation(stringBuffer.toString());
                seatEntity.setEndStation(endStation);
                seatEntity.setTrainCode(trainCode);
                seatEntity.setCoachNumber(coachNumber.toString());
            }else{
                return null;
            }
            seats.add(seatEntity);
        }

        if (p) {
            //获取到相应需要分配的席位
            List<SeatEntity> allocated = getAllocated(seats, planEntity);
            List<Long> ids = allocated.stream().map(item -> {
                return item.getSeatId();
            }).collect(Collectors.toList());
            //找出所有不在那计划百分比中的席位信息(即不需要修改的初始化数据)
            List<SeatEntity> unContain = seats.stream().filter(item -> {
                return !ids.contains(item.getSeatId());
            }).collect(Collectors.toList());
            //把修改部分添加进去
            unContain.addAll(allocated);
            return unContain;
        }else{
            return seats;
        }
    }

    private  Date getDate(String dateStr,int dataCount){
        LocalDateTime currDate = LocalDateTime.now();
        String toDay = currDate.format(oneFormate);//今天的时间
        toDay=toDay+" "+dateStr;
        Date caclet = TrainUtils.caclet(toDay, TrainUtils.formate, dataCount);
        return caclet;
    }
    /**
     * 根据车次代码查找出车厢的信息
     * @param trainCode
     * @param logicDelete
     * @return
     */
    private List<CarriageEntity> queryCoachByTrainCode(String trainCode, Integer logicDelete){
        if (trainCode!=null||logicDelete!=null){
         return    this.baseMapper.queryCoachByTrainCode(trainCode,logicDelete);
        }
        return null;
    }
    @Override
    public void updatePlanById(PlanEntity plan) {
        if (plan != null) {
            plan.setUpdateDate(new Date());
            this.baseMapper.updateById(plan);
        }
    }

    @Override
    @Transactional
    public ResponseData deletePlanBatchByIds(List<Long> planIds) {

        List<PlanEntity> planEntities = this.baseMapper.selectBatchIds(planIds);
        List<PlanEntity> collect = planEntities.stream().filter(item -> {
            return item.getLogicDelete().equals(CommonConstants.LogicDelete.no_delet.getValue());
        }).collect(Collectors.toList());
        List<String> trainCodes = collect.stream().map(x -> {
            return x.getTrainCode();
        }).distinct().collect(Collectors.toList());
        List<Long> coachNumbers = collect.stream().map(x -> {
            return x.getCoachNumber();
        }).distinct().collect(Collectors.toList());
        this.seatService.deleteBatchSeatsByTrainCodeAndCoachNumber(trainCodes,coachNumbers,CommonConstants.LogicDelete.delete.getValue(),1);
        this.baseMapper.deletePlanBatchByIds(planIds, CommonConstants.LogicDelete.delete.getValue());
        return ResponseData.ok();
    }

    @Override
    public List<PlanEntity> queryAllPlan(int logicDelete) {
        return this.baseMapper.queryAllPlan(logicDelete);
    }

    @Override
    public ResponseData getAddParameters(Long id) {
        System.out.println("id=============================="+id);
        String trainCode = null;
        if(id != null){
            PlanEntity planEntity = this.baseMapper.selectById(id);
            System.out.println(planEntity);
            trainCode = planEntity.getTrainCode();
        }
        List<PlanParamsVo> list = this.baseMapper.getPlanParameters(trainCode, CommonConstants.LogicDelete.no_delet.getValue());
        list.stream().forEach(paramsVo->{
            System.out.println(paramsVo);
            if(paramsVo.getRouteId() != null){
                List<String> stationNameList = this.baseMapper.getStationNameList(paramsVo.getRouteId(), CommonConstants.LogicDelete.no_delet.getValue());
                System.out.println(paramsVo.getRouteId() + ":::::::::" + stationNameList);
                paramsVo.setStationName(stationNameList);
            }
        });
        return ResponseData.ok().put("list", list);
    }
}
